package com.computergames.server.protocol;

import com.computergames.server.config.Config;
import com.computergames.server.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import java.util.zip.CRC32;
import java.nio.BufferUnderflowException;
import java.util.List;


/**
 * 必须和LengthFieldBasedFrameDecoder一起使用，确保接到的byteBuf消息是完整的
 */
@Slf4j
@ChannelHandler.Sharable
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Message message, List<Object> outlist) throws Exception {
        ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
        //1. 4字节的魔数
        byteBuf.writeBytes(new byte[]{'c','g','c','p'});
        //2. 1字节的协议版本
        byteBuf.writeByte(1);
        //3. 1字节的序列化方式 java 0， json 1
        byteBuf.writeByte(Config.getSerializerAlgorithm().ordinal());
        //4. 1字节的指令类型
        byteBuf.writeByte(message.getMessageType());
        //5. 4字节的请求序号，提供异步能力
        byteBuf.writeInt(message.getSequenceId());
        // 无意义，对齐填充凑齐16字节
        byteBuf.writeByte(0xff);
        //6. 获取内容的字节数组
        byte[] bytes = Config.getSerializerAlgorithm().serialize(message);
        //7. 长度，加上4字节校验码
        byteBuf.writeInt(bytes.length+4);
        //8. 写入内容
        byteBuf.writeBytes(bytes);
        //9. 计算CRC32校验码
        CRC32 crc = new CRC32();
        crc.update(byteBuf.nioBuffer(0, byteBuf.writerIndex()));
        //10. 将校验码写入缓冲区
        byteBuf.writeInt((int)crc.getValue());
        outlist.add(byteBuf);
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        try {
            int magicNum = byteBuf.readInt();
            if (magicNum != 0x63676370) {
                throw new IllegalArgumentException("不识别的协议包");
            }

            byte version = byteBuf.readByte();
            byte serializerAlgorithm = byteBuf.readByte();
            byte messageType = byteBuf.readByte();
            int sequenceId = byteBuf.readInt();
            // 读取并丢弃对齐填充
            byteBuf.readByte();

            int length = byteBuf.readInt();
            if (length < 0 || length > byteBuf.readableBytes()) {
                throw new BufferUnderflowException();
            }

            //长度减去4字节校验码
            byte[] bytes = new byte[length-4];
            byteBuf.readBytes(bytes);

            // 初始化 CRC32 计算器
            CRC32 crc32 = new CRC32();

            // 计算 CRC32 值
            crc32.update(byteBuf.nioBuffer(0, byteBuf.readerIndex()));

            // 检查 CRC32 校验和
            int calculatedCrc = (int)crc32.getValue();
            int receivedCrc = byteBuf.readInt(); // 从接下来的 4 字节中读取 CRC32
            if (calculatedCrc != receivedCrc) {
                throw new IllegalArgumentException("CRC32 校验失败");
            }

            SerializerEnum algorithm = SerializerEnum.values()[serializerAlgorithm];
            Class<?> messageClass = Message.getMessageClass(messageType);

            Object message = algorithm.deserialize(messageClass, bytes);

            list.add(message);
        } catch (IllegalArgumentException | BufferUnderflowException | IndexOutOfBoundsException e) {
            // 这些异常通常表示协议错误或数据不完整，可以考虑关闭连接
            log.error("解码错误，原因：", e);
            channelHandlerContext.close();
        } catch (RuntimeException e) {
            // 其他运行时异常也记录并关闭连接
            log.error("解码过程中遇到未知错误，原因：", e);
            channelHandlerContext.close();
        }
    }

}
